/*
 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */

'use strict';

var offerButton = document.getElementById('offerButton');
var answerButton = document.getElementById('answerButton');
var acceptButton = document.getElementById('acceptButton');
var hangupButton = document.getElementById('hangupButton');

var offerSDPSel = 'textarea#offerSDP';
var offerCandsSel = 'textarea#offerCandidates';
var answerSDPSel = 'textarea#answerSDP';
var answerCandsSel = 'textarea#answerCandidates';

var offerSDPTextarea = document.querySelector(offerSDPSel);
var offerCandidatesTextarea = document.querySelector(offerCandsSel);
var answerSDPTextarea = document.querySelector(answerSDPSel);
var answerCandidatesTextarea = document.querySelector(answerCandsSel);
var localCandidates = new Array();
var remoteCandidates = new Array();
// var servers = null;
var servers = {
  "iceServers": [{
      "url": "stun:121.41.87.159:3478"
  }]
};

var sdpConstraints = {
  'mandatory': {
    'OfferToReceiveAudio': true,
    'OfferToReceiveVideo': true
  }
};


answerButton.disabled = false;
hangupButton.disabled = true;
offerButton.onclick = offer;
answerButton.onclick = answer;
hangupButton.onclick = hangup;
acceptButton.onclick = accept;

var startTime;
var localVideo = document.getElementById('localVideo');
var remoteVideo = document.getElementById('remoteVideo');

localVideo.addEventListener('loadedmetadata', function() {
  trace('Local video videoWidth: ' + this.videoWidth +
    'px,  videoHeight: ' + this.videoHeight + 'px');
});

remoteVideo.addEventListener('loadedmetadata', function() {
  trace('Remote video videoWidth: ' + this.videoWidth +
    'px,  videoHeight: ' + this.videoHeight + 'px');
});

remoteVideo.onresize = function() {
  trace('Remote video size changed to ' +
    remoteVideo.videoWidth + 'x' + remoteVideo.videoHeight);
  // We'll use the first onsize callback as an indication that video has started
  // playing out.
  if (startTime) {
    var elapsedTime = window.performance.now() - startTime;
    trace('Setup time: ' + elapsedTime.toFixed(3) + 'ms');
    startTime = null;
  }
};

var localStream = null;
var answerStream = null;
var pc1;
var pc2;


function getName(pc) {
  return (pc === pc1) ? 'pc1' : 'pc2';
}

function getOtherPc(pc) {
  return (pc === pc1) ? pc2 : pc1;
}



function offer() {
  trace('Requesting local stream');
  offerButton.disabled = true;
  navigator.mediaDevices.getUserMedia({
    audio: true,
    video: true
  })
  .then(gotStream)
  .catch(function(e) {
    alert('getUserMedia() error: ' + e.name);
  });
}

function answer() {
  answerButton.disabled = true;
  hangupButton.disabled = false;
  createMyAnswer();
}

function accept() {
  acceptMyAnswer();
}

function hangup() {
  trace('Ending call');
  pc1.close();
  pc2.close();
  pc1 = null;
  pc2 = null;
  hangupButton.disabled = true;
  answerButton.disabled = false;
}

function gotStream(stream) {
  trace('Received local stream');
  // Call the polyfill wrapper to attach the media stream to this element.
  attachMediaStream(localVideo, stream);
  localStream = stream;
  answerButton.disabled = false;

  console.log(' got stream, creating sdp... \n');
  createMyOffer();
  
}

function createMyOffer(){
  trace('Starting call');
  startTime = window.performance.now();
  var videoTracks = localStream.getVideoTracks();
  var audioTracks = localStream.getAudioTracks();
  if (videoTracks.length > 0) {
    trace('Using video device: ' + videoTracks[0].label);
  }
  if (audioTracks.length > 0) {
    trace('Using audio device: ' + audioTracks[0].label);
  }


  pc1 = new RTCPeerConnection(servers);
  trace('Created local peer connection object pc1');
  pc1.onicecandidate = function(e) {
    onIceCandidate(pc1, e);
  };

  pc1.oniceconnectionstatechange = function(e) {
    onIceStateChange(pc1, e);
  };

  pc1.onaddstream = gotRemoteStream;
  pc1.addStream(localStream);
  trace('Added local stream to pc1');

  trace('pc1 createOffer start');
  pc1.createOffer(onCreateOfferSuccess, onCreateSessionDescriptionError);
}

function createMyAnswer(){

  if(localStream == null){
    navigator.mediaDevices.getUserMedia({
      audio: true,
      video: true
    })
    .then(function (stream){
      attachMediaStream(localVideo, stream);
      answerStream = stream;
      console.log(' got stream, creating sdp... \n');
      doCreateMyAnswer();
    })
    .catch(function(e) {
      alert('getUserMedia() error: ' + e.name);
    });
  }else{
    doCreateMyAnswer();
  }

 
}


function doCreateMyAnswer(){
  pc2 = new RTCPeerConnection(servers);
  trace('Created remote peer connection object pc2');
  pc2.onicecandidate = function(e) {
    onIceCandidate(pc2, e);
  };
  pc2.oniceconnectionstatechange = function(e) {
    onIceStateChange(pc2, e);
  };
  pc2.onaddstream = gotRemoteStream;
  if(answerStream != null){
    pc2.addStream(answerStream);
  }
  
  
  offerSDPTextarea = document.querySelector(offerSDPSel);
  // var desc = new RTCSessionDescription(offerSDPTextarea.value);
  // var desc = JSON.parse(offerSDPTextarea.value);
  var descraw = JSON.parse(offerSDPTextarea.value);
  var sdp = new String(descraw.sdp);
  var desc = new RTCSessionDescription(descraw);
  console.log('pc2 setRemoteDescription start --\n' + desc.sdp);
  pc2.setRemoteDescription(desc, function() {
    onSetRemoteSuccess(pc2);
  }, onSetSessionDescriptionError);
  console.log('pc2 createAnswer start');
  // Since the 'remote' side has no media stream we need
  // to pass in the right constraints in order for it to
  // accept the incoming offer of audio and video.
  pc2.createAnswer(onCreateAnswerSuccess, onCreateSessionDescriptionError,
      sdpConstraints);

  var candidates = JSON.parse(offerCandidatesTextarea.value);
  candidates.forEach(function(e){  
    pc2.addIceCandidate(new RTCIceCandidate(e)); 
  });
  
}


function acceptMyAnswer(){
  var descraw = JSON.parse(answerSDPTextarea.value);
  var desc = new RTCSessionDescription(descraw);
  pc1.setRemoteDescription(desc, function() {
    onSetRemoteSuccess(pc1);
  }, onSetSessionDescriptionError);

  answerCandidatesTextarea = document.querySelector(answerCandsSel);
  var candidates = JSON.parse(answerCandidatesTextarea.value);
  candidates.forEach(function(e){  
    pc1.addIceCandidate(new RTCIceCandidate(e)); 
  });

}



function onCreateSessionDescriptionError(error) {
  trace('Failed to create session description: ' + error.toString());
}

function onCreateOfferSuccess(desc) {
  console.log('Offer from pc1\n' + desc.sdp);
  offerSDPTextarea.value = JSON.stringify( desc ); 

  trace('pc1 setLocalDescription start');
  pc1.setLocalDescription(desc, function() {
    onSetLocalSuccess(pc1);
  }, onSetSessionDescriptionError);
}

function onSetLocalSuccess(pc) {
  trace(getName(pc) + ' setLocalDescription complete');
}

function onSetRemoteSuccess(pc) {
  trace(getName(pc) + ' setRemoteDescription complete');
}

function onSetSessionDescriptionError(error) {
  trace('Failed to set session description: ' + error.toString());
}

function gotRemoteStream(e) {
  // Call the polyfill wrapper to attach the media stream to this element.
  attachMediaStream(remoteVideo, e.stream);
  trace('received remote stream');
}

function onCreateAnswerSuccess(desc) {
  console.log('Answer from pc2:\n' + desc.sdp);
  answerSDPTextarea.value = JSON.stringify( desc ); 
  trace('pc2 setLocalDescription start');
  pc2.setLocalDescription(desc, function() {
    onSetLocalSuccess(pc2);
  }, onSetSessionDescriptionError);
}

function onIceCandidate(pc, event) {
  if (event.candidate) {
    // offerCandidatesTextarea.value = event.candidate;
    if(pc == pc1){
      localCandidates.push(event.candidate);
      offerCandidatesTextarea.value = JSON.stringify( localCandidates );
    }else{
      remoteCandidates.push(event.candidate);
      answerCandidatesTextarea.value = JSON.stringify( remoteCandidates );
    }
    console.log(getName(pc) + ' ICE candidate: \n' + event.candidate.candidate);
  }
}

function onAddIceCandidateSuccess(pc) {
  trace(getName(pc) + ' addIceCandidate success');
}

function onAddIceCandidateError(pc, error) {
  trace(getName(pc) + ' failed to add ICE Candidate: ' + error.toString());
}

function onIceStateChange(pc, event) {
  if (pc) {
    trace(getName(pc) + ' ICE state: ' + pc.iceConnectionState);
    console.log('ICE state change event---: ', event);
  }
}


